﻿using AVIS.OutBound.WizardAgent.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace AVIS.OutBound.WizardAgent
{
    /// <summary>
    /// 获取指定套餐包含有效车型组的Wizard服务
    /// </summary>
    public class WizardVehAvailRateAgent
    {
        /// <summary>
        /// 获取指定SIPPCode的单个车组信息
        /// </summary>
        /// <remarks>
        /// 对应于Wizard的接口：
        ///     请求：OTA_VehAvailRateRQ——Vehicle Availability and Rate Request
        ///     响应：OTA_VehAvailRateRS——Vehicle Availability and Rate Response
        /// </remarks>
        public CarGroupResponse GetCarGroupBySIPPCode(CarGroupsRequest request)
        {
            // 检查请求参数是否正确
            request.CheckRequest();

            // 请求Wizard接口获取指定SIPPCode的单个车组信息
            var response = WizardCacheHelper.GetResponseXml<CarGroupResponse>(request, (xml) =>
            {
                return WizardHttpClient.PostXml(xml);
            });

            // 解析车组套餐的XML
            if (!response.HasError)
            {
                var responseXDoc = XDocument.Parse(response.ResponseString);
                response.Data = FillCarGroupsWithXml(responseXDoc).FirstOrDefault();
            }

            return response;
        }

        /// <summary>
        /// 获取指定RateCode的车组信息
        /// </summary>
        /// <remarks>
        /// 对应于Wizard的接口：
        ///     请求：OTA_VehAvailRateRQ——Vehicle Availability and Rate Request
        ///     响应：OTA_VehAvailRateRS——Vehicle Availability and Rate Response
        /// </remarks>
        public CarGroupsResponse GetCarGroups(CarGroupsRequest request)
        {
            // 检查请求参数是否正确
            request.CheckRequest();

            // 请求Wizard接口获取指定套餐包含有效车型组（OTA_VehAvailRate）
            var response = WizardCacheHelper.GetResponseXml<CarGroupsResponse>(request, (xml) =>
            {
                return WizardHttpClient.PostXml(xml);
            });

            // 解析车组套餐的XML
            if (!response.HasError)
            {
                var responseXDoc = XDocument.Parse(response.ResponseString);
                response.Data = FillCarGroupsWithXml(responseXDoc);
            }
            return response;
        }

        /// <summary>
        /// 判断指定RateCode的车组信息是否已经存在缓存中
        /// </summary>
        /// <param name="request">请求参数</param>
        /// <returns></returns>
        public bool CarGroupsExistsInCache(CarGroupsRequest request)
        {
            return RedisHelper.KeyExists(request.GetCacheKey());
        }

        /// <summary>
        /// 从缓存中清除指定RateCode的车组信息
        /// </summary>
        /// <param name="request"></param>
        public void RemoveCarGroupsCache(CarGroupsRequest request)
        {
            WizardCacheHelper.RemoveCacheXml(request);
        }

        #region 解析车组的XML
        public List<CarGroupDto> FillCarGroupsWithXml(XDocument doc)
        {
            var list = new List<CarGroupDto>();

            // 查找有效的车型组信息
            XNamespace ns = XNamespace.Get(WizardConsts.XNamespace);
            var xVehList = from VehAvail in doc.Descendants(ns + "VehAvails").Elements(ns + "VehAvail")
                           where VehAvail.Element(ns + "VehAvailCore").Attribute("Status").Value == "Available"
                           select VehAvail;
            foreach (var xVeh in xVehList)
            {
                var carGroup = new CarGroupDto();
                list.Add(carGroup);

                // 解析车型组的基本信息（VehAvailCore节点）
                var xVehAvailCore = XmlHelpler.FindXElement(xVeh, "VehAvailCore", ns);
                ParseVehicleXml(XmlHelpler.FindXElement(xVehAvailCore, "Vehicle", ns), carGroup, ns);
                ParseRentalRateXml(XmlHelpler.FindXElement(xVehAvailCore, "RentalRate", ns), carGroup, ns);
                ParseTotalChargeXml(XmlHelpler.FindXElement(xVehAvailCore, "TotalCharge", ns), carGroup, ns);

                // Reference信息 (车辆功能特征（比如：自动挡、4座等）)
                var xReference = XmlHelpler.FindXElement(xVehAvailCore, "Reference", ns);

                //节点名为准
                var xVehicle = XmlHelpler.FindXElement(xVehAvailCore, "Vehicle", ns);
                if (xVehicle != null)
                {
                    ParseReferenceXml(xReference, xVehicle, carGroup, ns);
                }
                else
                {
                    ParseReferenceXml(xReference, null, carGroup, ns);
                }

                //ParseReferenceXml(xReference, carGroup, ns);

                // 套餐价格的限制里程数信息
                ParseRateDistanceXml(XmlHelpler.FindXElement(xVehAvailCore, "RateDistance", ns), carGroup, ns);

                // 套餐价格的收费标准
                ParseVehicleChargesXml(XmlHelpler.FindXElement(xVehAvailCore, "VehicleCharges", ns), carGroup, ns);

                // 套餐价格包含的保险项目
                ParsePricedCoveragesXml(XmlHelpler.FindXElement(xVeh, "PricedCoverages", ns), carGroup, ns);
            }

            return list;
        }

        public void ParseVehicleXml(XElement VehicleElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            var xVehMakeModel = XmlHelpler.FindXElement(VehicleElement, "VehMakeModel", ns);
            carGroup.ModelName = XmlHelpler.ParseValue(xVehMakeModel, "Name");
            carGroup.SIPPCode = XmlHelpler.ParseValue(xVehMakeModel, "Code");
            carGroup.PictureURL = XmlHelpler.ParseValue(XmlHelpler.FindXElement(VehicleElement, "PictureURL", ns));
        }

        public void ParseRentalRateXml(XElement RentalRateElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            var xRateQualifier = XmlHelpler.FindXElement(RentalRateElement, "RateQualifier", ns);
            carGroup.RateCategory = XmlHelpler.ParseValue(xRateQualifier, "RateCategory");
            carGroup.RateCode = XmlHelpler.ParseValue(xRateQualifier, "RateQualifier");

            var xCalculations = RentalRateElement.Descendants(ns + "Calculation");
            if (xCalculations.Count() >= 1)
            {
                carGroup.RentalLength = XmlHelpler.ParseValue(xCalculations.ElementAt(0), "Quantity");
                carGroup.RentalUnit = XmlHelpler.ParseValue(xCalculations.ElementAt(0), "UnitName");
            }
        }

        public void ParseTotalChargeXml(XElement TotalChargeElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            var strPrice = XmlHelpler.ParseValue(TotalChargeElement, "EstimatedTotalAmount");
            carGroup.Price = double.Parse(strPrice);
            carGroup.CurrencyCode = XmlHelpler.ParseValue(TotalChargeElement, "CurrencyCode");
        }

        public void ParseRateDistanceXml(XElement RateDistanceElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            var Unlimited = XmlHelpler.ParseValue(RateDistanceElement, "Unlimited");
            var Quantity = XmlHelpler.ParseValue(RateDistanceElement, "Quantity");
            var DistUnitName = XmlHelpler.ParseValue(RateDistanceElement, "DistUnitName");
            var VehiclePeriodUnitName = XmlHelpler.ParseValue(RateDistanceElement, "VehiclePeriodUnitName");
            if (Unlimited == "true")
            {
                carGroup.PriceInclue.Distance.Unlimited = true;
            }
            else
            {
                carGroup.PriceInclue.Distance.Unlimited = false;
                carGroup.PriceInclue.Distance.Quantity = Quantity;
                carGroup.PriceInclue.Distance.DistanceUnit = DistUnitName;
                carGroup.PriceInclue.Distance.PeriodUnit = VehiclePeriodUnitName;
            }
        }

        public void ParseVehicleChargesXml(XElement VehicleChargesElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            if (VehicleChargesElement == null)
            {
                return;
            }
            foreach (var xCharge in VehicleChargesElement.Elements(ns + "VehicleCharge"))
            {
                var IncludedInRate = XmlHelpler.ParseValue(xCharge, "IncludedInRate");
                var Purpose = XmlHelpler.ParseValue(xCharge, "Purpose");
                var Description = XmlHelpler.ParseValue(xCharge, "Description");

                if (IncludedInRate == "true" && Purpose != "1")
                {
                    carGroup.PriceInclue.VehicleCharges.Add(Description);
                }
                else if (IncludedInRate == "true" && Description.Contains("One way fee"))
                {
                    carGroup.PriceInclue.VehicleCharges.Add(Description);
                }
                else if (Description.Contains("Local Tax"))
                {
                    carGroup.PriceInclue.VehicleCharges.Add(Description);
                }
            }
        }

        public void ParsePricedCoveragesXml(XElement PricedCoveragesElement, CarGroupDto carGroup, XNamespace ns = null)
        {
            if (PricedCoveragesElement == null)
            {
                return;
            }

            foreach (var xPricedCoverage in PricedCoveragesElement.Elements(ns + "PricedCoverage"))
            {
                var IncludedInRate = XmlHelpler.ParseValue(XmlHelpler.FindXElement(xPricedCoverage, "Charge", ns), "IncludedInRate");
                var ChargeAmount = XmlHelpler.ParseValue(XmlHelpler.FindXElement(xPricedCoverage, "Charge", ns), "Amount");
                if (IncludedInRate == "true" && ChargeAmount == "0.00")
                {
                    var xCoverage = XmlHelpler.FindXElement(xPricedCoverage, "Coverage", ns);
                    var strCode = XmlHelpler.ParseValue(xCoverage, "Code");
                    var strContent = XmlHelpler.ParseValue(XmlHelpler.FindXElement(xCoverage, "Details", ns));

                    if (!carGroup.PriceInclue.Coverages.Exists(c => c.Code == strCode))
                        carGroup.PriceInclue.Coverages.Add(new PriceIncludeCoverageDto { Code = strCode, Content = strContent });
                }
            }
        }

        public void ParseReferenceXml(XElement ReferenceElement, XElement xVehicle, CarGroupDto carGroup, XNamespace ns = null)
        {
            if (ReferenceElement == null)
            {
                return;
            }

            var AirConditionInd = XmlHelpler.ParseValue(xVehicle, "AirConditionInd");//是否有空调
            var automatic = XmlHelpler.ParseValue(xVehicle, "TransmissionType").ToLower();//是否为自动挡



            var ReferenceType = XmlHelpler.ParseValue(ReferenceElement, "Type");  // Features
            var ReferenceID = XmlHelpler.ParseValue(ReferenceElement, "ID");
            if (ReferenceType == "Features")
            {
                carGroup.Feature = new CarFeatureDto(ReferenceID);

                if (automatic == "automatic")
                {
                    carGroup.Feature.IsAutomatic = true;
                }
                else if (automatic == "manual")
                {
                    carGroup.Feature.IsAutomatic = false;
                }

                if (AirConditionInd != null)
                {
                    carGroup.Feature.HasAirConditioning = automatic.Contains("true");
                }
            }
        }
        #endregion

        public void RemoveCache(double amount, CarGroupsRequest request)
        {
            var response = WizardCacheHelper.GetResponseXml<CarGroupsResponse>(request);

            if (!string.IsNullOrWhiteSpace(response.ResponseString))
            {
                var doc = XDocument.Parse(response.ResponseString);
                var carGroups = FillCarGroupsWithXml(doc);

                //var carGroup = carGroups.FirstOrDefault(c => c.SIPPCode == request.SIPPCode);
                //if (carGroup != null && carGroup.Price != amount)
                //{
                //    // 清空缓存文件
                //    WizardCacheHelper.RemoveCacheXml(request);
                //}
            }
        }
    }
}
